import axios from 'axios';
import qs from 'qs';
import { Message } from 'element-ui';
import { baseApi } from '@/config';
import { aesEncrypt, aesDecrypt } from '@utils/encrypt';
import { device } from '@utils/device-info';

const deviceInfo = device();
let options = {
  responseCodeFn: {},
  headers: {
    'Mobile-Type': deviceInfo.mobileType, // 操作系统(ios/andriod)
    'Mobile-Model': deviceInfo.mobileModel, // 手机型号（P7）
    'System-Version': deviceInfo.systemVersion, // 操作系统版本(6.0)
    'Device-ID': navigator.userAgent, // 系统
    'App-Version': '1.0.0', // app版本号
    'X-Requested-With': 'XMLHttpRequest',
    'Channel-Code': '0001',
  },
  message: Message,
};

const service = axios.create({
  baseURL: baseApi, // url = base url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 60000, // request timeout
});

service.interceptors.request.use(
  (config) => {
    // 数据加密
    if (process.env.NODE_ENV !== 'development') {
      const isPostJson = config.headers['Content-Type'] === 'application/json';
      const defaultEncrypt = isPostJson ? 'Y' : 'N';
      // 每次请求先重置Encrytion-Flag
      delete options.headers['Encrytion-Flag'];
      // 只对post application/json请求加密
      if (isPostJson) {
        const encrypted = aesEncrypt(config.data);
        config.data = { data: encrypted.text };
      }
      // 优先级：接口单独传 > setOptions > 默认
      options.headers['Encrytion-Flag'] =
        config.headers['Encrytion-Flag'] || options.headers['Encrytion-Flag'] || defaultEncrypt;
    } else {
      options.headers['Encrytion-Flag'] = config.headers['Encrytion-Flag'] || options.headers['Encrytion-Flag'] || 'N';
    }

    // 添加随机字符串
    config.url += `${config.url.indexOf('?') > -1 ? '&' : '?'}_cb=${new Date().getTime()}`;

    // 配置headers
    options.headers['X-Http-Forwarded-For'] = config.url;
    let { headers } = options;
    Object.keys(headers).forEach((header) => {
      config.headers[header] = headers[header];
    });

    return config;
  },
  (error) => {
    console.log(error); // for debug
    return Promise.reject(error);
  }
);

service.interceptors.response.use(
  (res) => {
    if (res.status === 200) {
      // 返回值解密
      if (res.data && res.headers['Encrytion-Flag'] === 'Y') {
        res.data = aesDecrypt(res.data);
      }

      // 登录过期
      if (res.data.code == 530000) {
        window.location.href = window.location.origin;
        options.message(res.data.msg);
        return;
      }

      let responseCodeFn = options.responseCodeFn[res.data.code];
      if (responseCodeFn) {
        responseCodeFn();
        return;
      }

      if (res.data.code !== 200 && !res.config.headers.noMes) {
        options.message(res.data.msg);
        throw new Error(`[http.js] Code: ${res.data.code} Message: ${res.data.msg}`);
      }
    } else {
      options.message.error(res.data.msg || 'error');
    }

    return res;
  },
  (error) => {
    // Do something with response error
    return Promise.reject(error);
  }
);

async function post(url, data, config = {}, type) {
  let contentType, body, responseType;

  switch (type) {
    case 'form':
      contentType = 'application/x-www-form-urlencoded';
      body = qs.stringify(data);
      break;
    case 'multi':
      contentType = 'multipart/form-data';
      responseType = config.responseType;
      body = new FormData();
      Object.keys(data).forEach((key) => {
        if (Array.isArray(data[key])) {
          data[key].forEach((value) => {
            body.append(key, value);
          });
        } else {
          let isBlob = Object.prototype.toString.call(data[key]).slice(8, -1) == 'Blob';
          if (isBlob) {
            body.append(key, data[key], data[key].name);
          } else {
            body.append(key, data[key]);
          }
        }
      });
      break;
    case 'json':
      contentType = 'application/json';
      body = data || {};
      break;
  }
  let res = await service({
    method: 'POST',
    url,
    headers: Object.assign(config.headers || {}, {
      'Content-Type': contentType,
    }),
    data: body,
    cancelToken: config.cancelToken || null,
    onUploadProgress: config.onProgress,
    responseType: config.responseType,
    timeout: config.timeout || 0,
  });
  if (config.responseType === 'blob') {
    return res;
  }
  return res.data;
}

async function put(url, data, config = {}, type) {
  let contentType, body;

  switch (type) {
    case 'form':
      contentType = 'application/x-www-form-urlencoded';
      body = qs.stringify(data);
      break;
    case 'json':
      contentType = 'application/json';
      body = data;
      break;
  }
  let res = await service({
    method: 'PUT',
    url,
    headers: Object.assign(config.headers || {}, {
      'Content-Type': contentType,
    }),
    data: body,
    timeout: config.timeout || 0,
  });
  return res.data;
}

async function get(url, data = null, config = {}) {
  let res = await service({
    method: 'GET',
    url,
    params: data,
    cancelToken: config.cancelToken || null,
    headers: Object.assign(config.headers || {}),
    timeout: config.timeout || 0,
  });
  return res.data;
}

async function getImgSrc(url, data = null, config = {}) {
  let res = await service({
    method: 'GET',
    url,
    params: data,
    headers: Object.assign(config.headers || {}),
    responseType: 'blob',
    timeout: config.timeout || 0,
  });
  //! 兼容华为V20浏览器 长按图片blob url下载不了
  return await new Promise((success) => {
    let reader = new FileReader();
    reader.onload = function (e) {
      success(e.target.result);
    };
    reader.readAsDataURL(res.data);
  });
}

async function getFileBlob(url, data = null, config = {}) {
  let res = await service({
    method: 'GET',
    url,
    params: data,
    headers: Object.assign(config.headers || {}),
    responseType: 'blob',
    timeout: config.timeout || 0,
  });
  return res;
}

async function ajaxdelete(url, data, config = {}) {
  let res = await service({
    method: 'DELETE',
    url,
    params: data,
    headers: Object.assign(config.headers || {}),
    timeout: config.timeout || 0,
  });
  return res.data;
}

function getToken() {
  return service.CancelToken.source();
}

function setOptions(opts) {
  Object.entries(opts).forEach(([key, value]) => {
    if (value instanceof Function || typeof value !== 'object') {
      options[key] = value;
      return;
    }
    options[key] = Object.assign(options[key], value);
  });
}

export default {
  ajaxdelete,
  get,
  getImgSrc,
  getFileBlob,
  async postForm(url, data, config = {}) {
    return post(url, data, config, 'form');
  },
  async postMulti(url, data, config = {}) {
    return post(url, data, config, 'multi');
  },
  async postJson(url, data, config = {}) {
    return post(url, data, config, 'json');
  },
  async putForm(url, data, config = {}) {
    return put(url, data, config, 'form');
  },
  async putJson(url, data, config = {}) {
    return put(url, data, config, 'json');
  },
  setOptions,
  getToken,
};
